home *** CD-ROM | disk | FTP | other *** search
- *************************** Motivation **********************************
-
- Many interactive programs read input line by line, but would like to
- provide line editing and history functionality to the end-user that
- runs the program.
-
- The input-edit package provides that functionality. As far as the
- programmer is concerned, the program only asks for the next line
- of input. However, until the user presses the RETURN key they can use
- emacs-style line editing commands and can traverse the history of lines
- previously typed.
-
- Other packages, such as GNU's readline, have greater capability but are
- also substantially larger. Input-edit is small, since it uses neither
- stdio nor any termcap features, and is also quite portable. It only uses
- \b to backspace and \007 to ring the bell on errors. Since it cannot
- edit multiple lines it scrolls long lines left and right on the same line.
-
- Input edit uses classic (not ANSI) C, and should run on any Unix
- system (BSD, SYSV or POSIX), PC's under DOS with MSC, TurboC or djgpp,
- PC's under OS/2 with gcc (EMX), or Vax/VMS. Porting the package to new
- systems basicaly requires code to read a character when it is typed without
- echoing it, everything else should be OK.
-
- I have run the package on:
-
- DECstation 5000, Ultrix 4.3 with cc 2.1 and gcc 2.3.3
- Sun Sparc 2, SunOS 4.1.1, with cc
- SGI Iris, IRIX System V.3, with cc
- PC using DOS with MSC
-
- The description below is broken into two parts, the end-user (editing)
- interface and the programmer interface. Send bug reports, fixes and
- enhancements to:
-
- Chris Thewalt (thewalt@ce.berkeley.edu)
- 5/3/93
-
- Thanks to the following people who have provided enhancements and fixes:
- Ron Ueberschaer, Christoph Keller, Scott Schwartz, Steven List,
- DaviD W. Sanderson, Goran Bostrom, Michael Gleason, Glenn Kasten,
- Edin Hodzic, Eric J Bivona, Kai Uwe Rommel, Danny Quah, Ulrich Betzler
-
- PS: I don't have, and don't want to add, a vi mode, sorry.
-
- ************************** End-User Interface ***************************
-
- Entering printable keys generally inserts new text into the buffer (unless
- in overwrite mode, see below). Other special keys can be used to modify
- the text in the buffer. In the description of the keys below, ^n means
- Control-n, or holding the CONTROL key down while pressing "n". Errors
- will ring the terminal bell.
-
- ^A/^E : Move cursor to beginning/end of the line.
- ^F/^B : Move cursor forward/backward one character.
- ESC-F : Move cursor forward one word.
- ESC-B : Move cursor backward one word.
- ^D : Delete the character under the cursor.
- ^H, DEL : Delete the character to the left of the cursor.
- ^K : Kill from the cursor to the end of line.
- ^L : Redraw current line.
- ^O : Toggle overwrite/insert mode. Initially in insert mode. Text
- added in overwrite mode (including yanks) overwrite
- existing text, while insert mode does not overwrite.
- ^P/^N : Move to previous/next item on history list.
- ^R/^S : Perform incremental reverse/forward search for string on
- the history list. Typing normal characters adds to the current
- search string and searches for a match. Typing ^R/^S marks
- the start of a new search, and moves on to the next match.
- Typing ^H or DEL deletes the last character from the search
- string, and searches from the starting location of the last search.
- Therefore, repeated DEL's appear to unwind to the match nearest
- the point at which the last ^R or ^S was typed. If DEL is
- repeated until the search string is empty the search location
- begins from the start of the history list. Typing ESC or
- any other editing character accepts the current match and
- loads it into the buffer, terminating the search.
- ^T : Toggle the characters under and to the left of the cursor.
- ^U : Deletes the entire line
- ^Y : Yank previously killed text back at current location. Note that
- this will overwrite or insert, depending on the current mode.
- TAB : By default adds spaces to buffer to get to next TAB stop
- (just after every 8th column), although this may be rebound by the
- programmer, as described below.
- NL, CR : returns current buffer to the program.
-
- DOS and ANSI terminal arrow key sequences are recognized, and act like:
-
- up : same as ^P
- down : same as ^N
- left : same as ^B
- right : same as ^F
-
- ************************** Programmer Interface ***************************
-
- The programmer accesses input-edit through these functions, and optionally
- through three additional function pointer hooks. The four functions are:
-
- char *getline(char *prompt)
-
- Prints the prompt and allows the user to edit the current line. A
- pointer to the line is returned when the user finishes by
- typing a newline or a return. Unlike GNU readline, the returned
- pointer points to a static buffer, so it should not be free'd, and
- the buffer contains the newline character. The user enters an
- end-of-file by typing ^D on an empty line, in which case the
- first character of the returned buffer is '\0'. Getline never
- returns a NULL pointer. The getline functions sets terminal modes
- needed to make it work, and resets them before returning to the
- caller. The getline function also looks for characters that would
- generate a signal, and resets the terminal modes before raising the
- signal condition. If the signal handler returns to getline,
- the screen is automatically redrawn and editing can continue.
- Getline now requires both the input and output stream be connected
- to the terminal (not redirected) so the main program should check
- to make sure this is true. If input or output have been redirected
- the main program should use buffered IO (stdio) rather than
- the slow 1 character read()s that getline uses.
-
- void gl_setwidth(int width)
-
- Set the width of the terminal to the specified width. The default
- width is 80 characters, so this function need only be called if the
- width of the terminal is not 80. Since horizontal scrolling is
- controlled by this parameter it is important to get it right.
-
- void gl_histadd(char *buf)
-
- The gl_histadd function checks to see if the buf is not empty or
- whitespace, and also checks to make sure it is different than
- the last saved buffer to avoid repeats on the history list.
- If the buf is a new non-blank string a copy is made and saved on
- the history list, so the caller can re-use the specified buf.
-
- void gl_strwidth(size_t (*func)())
- The gl_strwidth function allows the caller to supply a pointer to
- a prompt width calculation function (strlen by default). This
- allows the caller to embed escape sequences in the prompt and then
- tell getline how many screen spaces the prompt will take up.
-
- The main loop in testgl.c, included in this directory, shows how the
- input-edit package can be used:
-
- extern char *getline();
- extern void gl_histadd();
- main()
- {
- char *p;
- do {
- p = getline("PROMPT>>>> ");
- gl_histadd(p);
- fputs(p, stdout);
- } while (*p != 0);
- }
-
- In order to allow the main program to have additional access to the buffer,
- to implement things such as completion or auto-indent modes, three
- function pointers can be bound to user functions to modify the buffer as
- described below. By default gl_in_hook and gl_out_hook are set to NULL,
- and gl_tab_hook is bound to a function that inserts spaces until the next
- logical tab stop is reached. The user can reassign any of these pointers
- to other functions. Each of the functions bound to these hooks receives
- the current buffer as the first argument, and must return the location of
- the leftmost change made in the buffer. If the buffer isn't modified the
- functions should return -1. When the hook function returns the screen is
- updated to reflect any changes made by the user function.
-
- int (*gl_in_hook)(char *buf)
-
- If gl_in_hook is non-NULL the function is called each time a new
- buffer is loaded. It is called when getline is entered, with an
- empty buffer, it is called each time a new buffer is loaded from
- the history with ^P or ^N, and it is called when an incremental
- search string is accepted (when the search is terminated). The
- buffer can be modified and will be redrawn upon return to getline().
-
- int (*gl_out_hook)(char *buf)
-
- If gl_out_hook is non-NULL it is called when a line has been
- completed by the user entering a newline or return. The buffer
- handed to the hook does not yet have the newline appended. If the
- buffer is modified the screen is redrawn before getline returns the
- buffer to the caller.
-
- int (*gl_tab_hook)(char *buf, int prompt_width, int *cursor_loc)
-
- If gl_tab_hook is non-NULL, it is called whenever a tab is typed.
- In addition to receiving the buffer, the current prompt width is
- given (needed to do tabbing right) and a pointer to the cursor
- offset is given, where a 0 offset means the first character in the
- line. Not only does the cursor_loc tell the programmer where the
- TAB was received, but it can be reset so that the cursor will end
- up at the specified location after the screen is redrawn.
-